/*
* ===================================================
*
*       Filename:  free.c
*
*
*        Created:  10/15/2011 12:27:43 AM
*       Revision:  none
*       Compiler:  gcc
*
*         Author:  durand_y, <durand.yoan@gmail.com>
*
* ===================================================
*/
#include "malloc.h"

s_map       *g_map_list;
static void *search(void              *ptr,
                    s_map             *map)
{
    s_block *b = NULL;
    s_block *elt = NULL;

    b = map->block;
    elt = ptr;

    while ((b != NULL) && (b->end != elt))
        b = b->next;
    return (b);
}

void        free(void            *ptr)
{
    s_block *elt = NULL;
    s_block *b = NULL;
    s_map   *map = NULL;

    elt = ptr;
    b = g_map_list->block;
    map = g_map_list;
    while (map != NULL)
    {
        if ((b = search(ptr, map)) != NULL)
        {
          if ((is_last_on_map (map, ptr)) == 1)
          {
             munmap(map, map->block->size);
             return;
          }
          else
          {
              b->state = FREE;
              fusion(map);
              return;
          }
        }
        else
            map = map->next_map;
    }
}

int         is_last_on_map(s_map    *map,
                           void     *ptr)
{
    s_block *b = NULL;

    if (search(ptr, map) != NULL)
    {
        b = map->block;
        int     cpt = 0;
        if (search(ptr, map))
        while (b != NULL)
        {
            if (b->state == NON_FREE)
                cpt++;
            b = b->next;
        }
        if (cpt == 1)
            return (1);
        else
            return (0);
    }
    else
        return (0);
}

void        fusion(s_map    *map)
{
    s_block *b = NULL;
    void    *ptr = NULL;
    char    *s = NULL;
    size_t    new_size = 0;
    b = map->block;

    while (b != NULL)
    {
        if ((b->state == FREE) && (b->next->state == FREE))
        {
            ptr = b->end;
            s = ptr;
            s = s + sizeof (s_block);
            new_size = (long unsigned int) s % sizeof (size_t);
            b->size += b->next->size + sizeof (s_block) + new_size;
            b->next = b->next->next;
            fusion(map);
        }
        b = b->next;
    }
}

static void *decal(s_block  *b,
                   void     *ptr,
                   char     **s)
{

    ptr = b->end;
    *s = ptr;
    *s += b->size / 2;
    return (ptr);
}

void        split(s_block   *b,
                  size_t    size)
{
    void    *ptr = NULL;
    void    *ptr2 = NULL;
    char    *s = NULL;
    s_block *new = NULL;

    if ((b->size >= size) && ((b->size / 2) >= size))
    {
        ptr = decal(b, ptr, &s);
        ptr2 = b->next;
        ptr = s + (long unsigned int)s % sizeof (size_t) + sizeof (s_block);
        if (ptr < ptr2)
        {
           ptr = decal(b, ptr, &s);
            ptr = s;
            new = ptr;
            s += (long unsigned int)s % sizeof (size_t) + sizeof (s_block);
            ptr = s;
            new->end = ptr;
            new->size = b->size / 2;
            new->next = b->next;
            new->state = FREE;
            b->next = new;
        }
    }
}
